﻿#region << 文 件 说 明 >>

/*----------------------------------------------------------------
// 文件名称：NumTextBoxBehavior
// 创 建 者：杨程
// 创建时间：2021/11/19 16:41:55
// 文件版本：V1.0.0
// ===============================================================
// 功能描述：
//
//
//----------------------------------------------------------------*/

#endregion

namespace Vampirewal.Core.WPF.Theme;

/// <summary>
/// 给TextBox添加行为，使其变成只能输入数字格式的
/// </summary>
public class NumTextBoxBehavior : Behavior<TextBoxBase>
{
    #region 属性

    public static readonly DependencyProperty NumTypeProperty = DependencyProperty.Register("NumType", typeof(Type), typeof(NumTextBoxBehavior));

    public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register("MaxValue", typeof(decimal), typeof(NumTextBoxBehavior)
        , new FrameworkPropertyMetadata(new PropertyChangedCallback(CheckProperty)));

    public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register("MinValue", typeof(decimal), typeof(NumTextBoxBehavior)
        , new FrameworkPropertyMetadata(new PropertyChangedCallback(CheckProperty)));

    public static readonly DependencyProperty PointLenthProperty = DependencyProperty.Register("PointLenth", typeof(int), typeof(NumTextBoxBehavior));
    public static readonly DependencyProperty NumberLengthProperty = DependencyProperty.Register("NumberLength", typeof(int), typeof(NumTextBoxBehavior));

    public enum Type
    { 
        Decimal, 
        UDecimal,
        Int,
        UInt 
    }

    /// <summary>
    /// 设置或获取textbox的输入数据类型
    /// </summary>
    public Type NumType
    {
        get { return (Type)GetValue(NumTypeProperty); }
        set { SetValue(NumTypeProperty, value); }
    }

    /// <summary>
    /// 设定或获取最大值
    /// </summary>
    public decimal MaxValue
    {
        get { return (decimal)GetValue(MaxValueProperty); }
        set { SetValue(MaxValueProperty, value); }
    }

    /// <summary>
    /// 设定或获取最小值
    /// </summary>
    public decimal MinValue
    {
        get { return (decimal)GetValue(MinValueProperty); }
        set { SetValue(MinValueProperty, value); }
    }

    /// <summary>
    /// 设置或获取小数点前的位数
    /// </summary>
    public int NumberLength
    {
        get { return (int)GetValue(NumberLengthProperty); }
        set { SetValue(NumberLengthProperty, value); }
    }

    /// <summary>
    /// 设置或获取小数点后位数长度
    /// </summary>
    public int PointLenth
    {
        get { return (int)GetValue(PointLenthProperty); }
        set { SetValue(PointLenthProperty, value); }
    }

    #endregion

    public NumTextBoxBehavior()
    {
        MinValue = decimal.MinValue;
        MaxValue = decimal.MaxValue;
        PointLenth = 4;
        NumberLength = 18;
        NumType = Type.Decimal;
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        base.AssociatedObject.KeyDown += new KeyEventHandler(AssociatedObject_KeyDown);
        base.AssociatedObject.TextChanged += new TextChangedEventHandler(AssociatedObject_TextChanged);
        base.AssociatedObject.GotFocus += new RoutedEventHandler(AssociatedObject_GotFocus);
        base.AssociatedObject.LostFocus += new RoutedEventHandler(AssociatedObject_LostFocus);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        base.AssociatedObject.KeyDown -= new KeyEventHandler(AssociatedObject_KeyDown);
        base.AssociatedObject.TextChanged -= new TextChangedEventHandler(AssociatedObject_TextChanged);
        base.AssociatedObject.GotFocus -= new RoutedEventHandler(AssociatedObject_GotFocus);
        base.AssociatedObject.LostFocus -= new RoutedEventHandler(AssociatedObject_LostFocus);
    }

    private string val = "";

    /// <summary>
    /// 设定最大值最小值依赖属性回调函数
    /// </summary>
    /// <param name="d"></param>
    /// <param name="e"></param>
    private static void CheckProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        NumTextBoxBehavior ntb = d as NumTextBoxBehavior;
        if (ntb.MaxValue < ntb.MinValue)
            ntb.MaxValue = ntb.MinValue;
    }

    /// <summary>
    /// 重写KeyDown事件，提供与事件有关的数据，过滤输入数据格式
    /// </summary>
    /// <param name="e"></param>
    private void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
    {
        TextBox tb = (TextBox)sender;
        string txt = tb.Text;
        int ind = tb.CaretIndex;

        if (txt.Contains("."))
        {
            if (txt.Split('.')[1].Length >= PointLenth && ind > txt.Split('.')[0].Length && tb.SelectionLength == 0)//控制小数点后输入位数
            {
                e.Handled = true;
                return;
            }
            else if (txt.Split('.')[0].Length >= NumberLength && ind <= txt.Split('.')[0].Length)//控制小数点前输入位数（有小数点）
            {
                e.Handled = true;
                return;
            }
        }
        else if (txt.Length == NumberLength && e.Key != Key.Decimal && e.Key != Key.OemPeriod)//控制小数点前输入位数（无小数点）
        {
            e.Handled = true;
            return;
        }

        if (e.Key == Key.Decimal || e.Key == Key.OemPeriod)
        {
            val = ".";
        }
        else
        {
            val = "";
        }
        switch (NumType)
        {
            case Type.UInt:
                //屏蔽非法按键
                if ((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key.ToString() == "Tab")
                {
                    e.Handled = false;
                }
                else if (((e.Key >= Key.D0 && e.Key <= Key.D9)) && e.KeyboardDevice.Modifiers != ModifierKeys.Shift)
                {
                    e.Handled = false;
                }
                else
                {
                    e.Handled = true;
                    if (e.Key.ToString() != "RightCtrl")
                    { }
                }
                break;

            case Type.Int:
                //屏蔽非法按键
                if ((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Subtract || e.Key.ToString() == "Tab")
                {
                    if ((txt.Contains("-") || tb.CaretIndex != 0) && e.Key == Key.Subtract)
                    {
                        e.Handled = true;
                        return;
                    }
                    e.Handled = false;
                }
                else if (((e.Key >= Key.D0 && e.Key <= Key.D9) || e.Key == Key.OemMinus) && e.KeyboardDevice.Modifiers != ModifierKeys.Shift)
                {
                    if ((txt.Contains("-") || tb.CaretIndex != 0) && e.Key == Key.OemMinus)
                    {
                        e.Handled = true;
                        return;
                    }
                    e.Handled = false;
                }
                else
                {
                    e.Handled = true;
                    if (e.Key.ToString() != "RightCtrl")
                    { }
                }
                break;

            case Type.Decimal:
                //屏蔽非法按键
                if ((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Decimal || e.Key == Key.Subtract || e.Key.ToString() == "Tab")
                {
                    if (txt.Contains(".") && e.Key == Key.Decimal)
                    {
                        e.Handled = true;
                        return;
                    }
                    else if ((txt.Contains("-") || tb.CaretIndex != 0) && e.Key == Key.Subtract)
                    {
                        e.Handled = true;
                        return;
                    }
                    e.Handled = false;
                }
                else if (((e.Key >= Key.D0 && e.Key <= Key.D9) || e.Key == Key.OemPeriod || e.Key == Key.OemMinus) && e.KeyboardDevice.Modifiers != ModifierKeys.Shift)
                {
                    if (txt.Contains(".") && e.Key == Key.OemPeriod)
                    {
                        e.Handled = true;
                        return;
                    }
                    else if ((txt.Contains("-") || tb.CaretIndex != 0) && e.Key == Key.OemMinus)
                    {
                        e.Handled = true;
                        return;
                    }
                    e.Handled = false;
                }
                else
                {
                    e.Handled = true;
                    if (e.Key.ToString() != "RightCtrl")
                    { }
                }
                break;

            case Type.UDecimal:
            default:
                //屏蔽非法按键
                if ((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Decimal || e.Key.ToString() == "Tab")
                {
                    if (txt.Contains(".") && e.Key == Key.Decimal)
                    {
                        e.Handled = true;
                        return;
                    }
                    e.Handled = false;
                }
                else if (((e.Key >= Key.D0 && e.Key <= Key.D9) || e.Key == Key.OemPeriod) && e.KeyboardDevice.Modifiers != ModifierKeys.Shift)
                {
                    if (txt.Contains(".") && e.Key == Key.OemPeriod)
                    {
                        e.Handled = true;
                        return;
                    }
                    e.Handled = false;
                }
                else
                {
                    e.Handled = true;
                    if (e.Key.ToString() != "RightCtrl")
                    { }
                }

                break;
        }
    }

    /// <summary>
    ///粘贴内容过滤，设定最大值、最小值，限制小数点输入长度
    /// </summary>
    /// <param name="e"></param>
    private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox tb = (TextBox)sender;

        int t1 = tb.Text.Length;
        if (t1 != 0)//用于是否可以将文本空置空
        {
            decimal d = 0;
            if (tb.Text != "-" && tb.Text != "." && tb.Text != "-0" && tb.Text != "-." && tb.Text != "-0." && val != ".")
            {
                if (decimal.TryParse(tb.Text, out d))
                {
                    if (NumType == Type.Decimal || NumType == Type.UDecimal)
                    {
                        if (d.ToString().Split('.')[0].Length > NumberLength)//
                        {
                            d = 0;
                        }
                        else
                        {
                            d = Math.Round(d, PointLenth, MidpointRounding.AwayFromZero);
                        }
                    }
                    else
                        if (d.ToString().Split('.')[0].Length > NumberLength)//
                    {
                        d = 0;
                    }
                    else
                    {
                        d = Math.Round(d, 0, MidpointRounding.AwayFromZero);
                    }
                }
                int t2 = d.ToString().Length;
                if (Math.Abs(t1 - d.ToString().Length) > 0)
                {
                    tb.Text = d.ToString();
                    tb.CaretIndex = d.ToString().Length;
                }
                else
                {
                    tb.Text = d.ToString();
                }
            }
            if ((NumType == Type.UDecimal || NumType == Type.UInt) && tb.Text.Contains("-"))
            {
                tb.Text = Math.Abs(d).ToString();
            }
            if ((NumType == Type.UInt || NumType == Type.Int) && tb.Text.Contains("."))
            {
                tb.Text = int.Parse(d.ToString()).ToString();
            }
        }
    }

    /// <summary>
    ///如果数据是0，得到光标，清空数据
    /// </summary>
    /// <param name="e"></param>
    private void AssociatedObject_GotFocus(object sender, RoutedEventArgs e)
    {
        TextBox tb = (TextBox)sender;

        decimal num = 0;
        if (decimal.TryParse(tb.Text, out num))
        {
            if (num != 0)
            {
                return;
            }
        }

        tb.Text = string.Empty;
    }

    /// <summary>
    ///失去光标，确定最大值最小值
    /// </summary>
    /// <param name="e"></param>
    private void AssociatedObject_LostFocus(object sender, RoutedEventArgs e)
    {
        TextBox tb = (TextBox)sender;

        decimal d = 0;
        if (decimal.TryParse(tb.Text, out d))
        {
            if (d < MinValue)
            {
                d = MinValue;
            }
            else if (d > MaxValue)
            {
                d = MaxValue;
            }

            if (NumType == Type.Decimal)
                tb.Text = d.ToString("N" + PointLenth);
            else
                tb.Text = d.ToString();
        }
        else if (string.IsNullOrEmpty(tb.Text))
        {
            tb.Text = "0";
        }
        else
        {
            tb.Text = d.ToString();
        }
    }
}